/**
 * @author lianbo
 * @date 2020-11-09 14:56:40
 * @Description: 2d下的矩阵变换
 *
 *      m00 m01 m02
 *      m10 m11 m12
 *      m20 m21 m22
 *
 */
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Matrix3x3 {
    pub m00: f64,
    pub m01: f64,
    pub m02: f64,
    pub m10: f64,
    pub m11: f64,
    pub m12: f64,
    pub m20: f64,
    pub m21: f64,
    pub m22: f64,
}

impl Matrix3x3 {
    pub fn new() -> Self {
        Self {
            m00: 1.0,
            m01: 0.0,
            m02: 0.0,
            m10: 0.0,
            m11: 1.0,
            m12: 0.0,
            m20: 0.0,
            m21: 0.0,
            m22: 1.0,
        }
    }
    /*
     *    x'           m00 m01 m02   Tx
     *    y'   = T(p)= m10 m11 m12 * Ty
     *    1            m20 m21 m22   1
     */
    pub fn translate(&mut self, x: f64, y: f64) {
        self.m02 = self.m02 + self.m00 * x + self.m01 * y;
        self.m12 = self.m12 + self.m10 * x + self.m11 * y;
    }
    /*
     *         cos -sin  0
     *         sin cos  0
     *         0   0    1
     *
     */
    pub fn rotate(&mut self, alpha: f64) {
        let cos = alpha.cos();
        let sin = alpha.sin();
        let mut r_mat = Matrix3x3::new();
        r_mat.m00 = cos;
        r_mat.m01 = -sin;
        r_mat.m10 = sin;
        r_mat.m11 = cos;
        self.multiply(&r_mat);
    }

    pub fn scale(&mut self, s_x: f64, s_y: f64) {
        self.m00 = self.m00 * s_x;
        self.m01 *= s_y;
        self.m10 *= s_x;
        self.m11 *= s_y;
    }

    pub fn apply(&self, x: f64, y: f64) -> (f64, f64) {
        let x1 = self.m00 * x + self.m01 * y + self.m02;
        let y1 = self.m10 * x + self.m11 * y + self.m12;
        (x1, y1)
    }

    pub fn multiply(&mut self, mat: &Matrix3x3) {
        let m00 = self.m00 * mat.m00 + self.m01 * mat.m10 + self.m02 * mat.m20;
        let m01 = self.m00 * mat.m01 + self.m01 * mat.m11 + self.m02 * mat.m21;
        let m02 = self.m00 * mat.m02 + self.m01 * mat.m12 + self.m02 * mat.m22;

        let m10 = self.m10 * mat.m00 + self.m11 * mat.m10 + self.m12 * mat.m20;
        let m11 = self.m10 * mat.m01 + self.m11 * mat.m11 + self.m12 * mat.m21;
        let m12 = self.m10 * mat.m02 + self.m11 * mat.m12 + self.m12 * mat.m22;

        let m20 = self.m20 * mat.m00 + self.m21 * mat.m10 + self.m22 * mat.m20;
        let m21 = self.m20 * mat.m01 + self.m21 * mat.m11 + self.m22 * mat.m21;
        let m22 = self.m20 * mat.m02 + self.m21 * mat.m12 + self.m22 * mat.m22;

        self.m00 = m00;
        self.m01 = m01;
        self.m02 = m02;

        self.m10 = m10;
        self.m11 = m11;
        self.m12 = m12;

        self.m20 = m20;
        self.m21 = m21;
        self.m22 = m22;
    }

    /**
     * @date 2020-11-19 09:43:58
     * @Description: 解析出位置旋转缩放
     */
    pub fn decompose(&self) -> (f64, f64, f64, f64, f64) {
        let a = self.m00;
        let b = self.m10;
        let c = self.m01;
        let d = self.m11;

        let skew_x = -c.atan2(d);
        let skew_y = b.atan2(a);

        let delta = (skew_x + skew_y).abs();
        let (mut x, mut y, mut rot, mut scale_x, mut scale_y) = (0.0, 0.0, 0.0, 0.0, 0.0);

        if delta < 0.00001 || (std::f64::consts::PI * 2.0 - delta).abs() < 0.00001 {
            rot = skew_y;
        } else {
            rot = 0.0;
        }

        // next set scale
        scale_x = (a * a + b * b).sqrt();
        scale_y = (c * c + d * d).sqrt();

        // next set position
        x = self.m02;
        y = self.m12;
        (x, y, rot, scale_x, scale_y)
    }

    /**
     * @date 2020-11-09 15:52:35
     * @Description: 通过逆矩阵从局部坐标转世界坐标
     */
    pub fn apply_inverse(&self, (pos_x, pos_y): (f64, f64)) -> (f64, f64) {
        let (mut new_pos_x, mut new_pos_y) = (0.0, 0.0);

        let id = 1.0 / (self.m00 * self.m11 + self.m01 * -self.m10);

        let x = pos_x;
        let y = pos_y;

        new_pos_x = self.m11 * id * x
            + -self.m01 * id * y
            + (self.m12 * self.m01 - self.m02 * self.m11) * id;
        new_pos_y = self.m00 * id * y
            + -self.m10 * id * x
            + (-self.m12 * self.m00 + self.m02 * self.m10) * id;

        (new_pos_x, new_pos_y)
    }

    /**
     * @date 2020-12-08 20:34:30
     * @Description: 逆矩阵
     */
    pub fn invert(&mut self) -> &mut Self {
        let a1 = self.m00;
        let b1 = self.m10;
        let c1 = self.m01;
        let d1 = self.m11;
        let tx1 = self.m02;
        let n = a1 * d1 - b1 * c1;
        self.m00 = d1 / n;
        self.m10 = -b1 / n;
        self.m01 = -c1 / n;
        self.m11 = a1 / n;
        self.m02 = (c1 * self.m12 - d1 * tx1) / n;
        self.m12 = -(a1 * self.m12 - b1 * tx1) / n;
        self
    }

    /**
     * @date 2021-04-16 00:07:47
     * @Description: 转置
     */
    pub fn transpose(&mut self) -> &mut Self {
        let tmp = self.m01;
        self.m01 = self.m10;
        self.m10 = tmp;
        let tmp = self.m02;
        self.m02 = self.m20;
        self.m20 = tmp;
        let tmp = self.m12;
        self.m12 = self.m21;
        self.m21 = tmp;
        self
    }

    /**
     * @date 2020-12-08 20:07:50
     * @Description: 水平方向上的错切变换（平行于X轴的变换）
     */
    pub fn shear_tf_x(&mut self, dt: f64) -> &mut Self {
        self.m10 = dt;
        self
    }

    pub fn shear_tf_y(&mut self, dt: f64) -> &mut Self {
        self.m01 = dt;
        self
    }

    pub fn x_axis_reflection() -> Matrix3x3 {
        let mut mat = Matrix3x3::new();
        mat.m11 = -1.0;
        mat
    }

    pub fn y_axis_reflection() -> Matrix3x3 {
        let mut mat = Matrix3x3::new();
        mat.m00 = -1.0;
        mat
    }

    pub fn xy_axis_reflection() -> Matrix3x3 {
        let mut mat = Matrix3x3::new();
        mat.m00 = -1.0;
        mat.m11 = -1.0;
        mat
    }
}
